#!/usr/bin/env python
"""
Matplotlib Animation Example

author: Jake Vanderplas
email: vanderplas@astro.washington.edu
website: http://jakevdp.github.com
license: BSD
Please feel free to use and modify this, but keep the above information. Thanks!
"""

import numpy as np
from matplotlib import pyplot as plt

from matplotlib import animation
import sys
import time

if len(sys.argv) == 6:
    XLIMITS = (float(sys.argv[1]), float(sys.argv[2]))
    YLIMITS = (float(sys.argv[3]), float(sys.argv[4]))
    ESCALA = float(sys.argv[5])
else:
    XLIMITS = (0, 3)
    YLIMITS = (0, 3.3)
    ESCALA = 3.3 / 1024

F_SAMPLE = 1000
POINTS_IN_SCREEN = (XLIMITS[1]-XLIMITS[0]) * F_SAMPLE

POINTS_PER_FRAME = 20
EXPECTED_TIME_PER_SCREEN = XLIMITS[1] - XLIMITS[0]


# First set up the figure, the axis, and the plot element we want to animate
fig = plt.figure()
ax = plt.axes(xlim=XLIMITS, ylim=YLIMITS)
line, = ax.plot([], [], lw=2)

actual = time.time()
accum_error = 0

# initialization function: plot the background of each frame
def init():
   global line
   line.set_data([], [])
   return line,

#precompute the x and y values
x = np.linspace(XLIMITS[0], XLIMITS[1], POINTS_IN_SCREEN)
y = np.zeros(POINTS_IN_SCREEN)

frame_num = POINTS_IN_SCREEN/POINTS_PER_FRAME - 1
# animation function.  This is called sequentially
def plot_frame(i):
   global x, y, line, actual, last_frame, POINTS_PER_FRAME, accum_error, frame_num

   frame_num += 1
   now = time.time()

   if i == 0:
      accum_error = 0
      actual = now - EXPECTED_TIME_PER_SCREEN

   if frame_num == POINTS_IN_SCREEN/POINTS_PER_FRAME:
      y = np.zeros(POINTS_IN_SCREEN) # reset the Y vector
      elapsed = (now - actual)
      delta = EXPECTED_TIME_PER_SCREEN - elapsed
      accum_error += delta
      sys.stderr.write("Plot %i frames in %s seconds [Err %s AccErr %s seconds].\n" % (frame_num, elapsed, delta, accum_error))
      if accum_error < 0 and delta < 0:
         POINTS_PER_FRAME += (POINTS_PER_FRAME/4 if accum_error < -5 else POINTS_PER_FRAME/2) if accum_error < delta else 1
      elif accum_error > 0 and delta > 0:
         POINTS_PER_FRAME -= (POINTS_PER_FRAME/4 if accum_error >  5 else POINTS_PER_FRAME/2) if accum_error > delta else 1 
      elif abs(accum_error) > 1.5*abs(delta):
         if delta < 0:
            POINTS_PER_FRAME += POINTS_PER_FRAME/4
         else:
            POINTS_PER_FRAME -= POINTS_PER_FRAME/4


      actual = now
      frame_num = 0
   
   for j in range(frame_num*POINTS_PER_FRAME, (frame_num+1)*POINTS_PER_FRAME):
      read = sys.stdin.readline()
      sys.stdout.write(read)
      y[j] = int(read) * ESCALA

   line.set_data(x, y)
   return line,


# call the animator.  blit=True means only re-draw the parts that have changed.
anim = animation.FuncAnimation(fig, plot_frame, init_func=init, interval=0, blit=True)

plt.show()
